


/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
   _____                        _    _ _ _ _         _           _         ____                  _
  / ____|                      | |  | (_) | |       | |         | |       |  _ \                | |
 | |  __ _ __ ___  ___ _ __    | |__| |_| | |       | | __ _  __| | ___   | |_) | __ _ _ __ ___ | |__   ___   ___
 | | |_ | '__/ _ \/ _ \ '_ \   |  __  | | | |   _   | |/ _` |/ _` |/ _ \  |  _ < / _` | '_ ` _ \| '_ \ / _ \ / _ \
 | |__| | | |  __/  __/ | | |  | |  | | | | |  | |__| | (_| | (_| |  __/  | |_) | (_| | | | | | | |_) | (_) | (_) |
  \_____|_|  \___|\___|_| |_|  |_|  |_|_|_|_|   \____/ \__,_|\__,_|\___|  |____/ \__,_|_| |_| |_|_.__/ \___/ \___/

<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/

//
// Created by Administrator on 2019/6/20.
//


/**
 * Copyright (c) 2021 - @RuanQiZhang All rights reserved
 * 
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE. 
 *
 * @file      samu_iic.c
 * @brief     pType source file
 * @version   0.0.1
 * @author    Ruan QiZhang
 * @date      2023-01-12
 *
 */
 

 #include "simu_master_iic.h"
 

#define USE_HIGH_SPEED  ( 0 )    
#define SI2C_ADDR_W(addr) (addr & 0xfe)
#define SI2C_ADDR_R(addr) (addr | 0x01)

 void simu_miic_start( const software_mi2c_t* i2c ){
 

	if (i2c->set_sda_mode) i2c->set_sda_mode( 0 );
	i2c->sda_out( 1 );
	i2c->scl_out( 1 );
	i2c->delay();   
	i2c->sda_out( 0 );
	i2c->delay();   
	i2c->scl_out( 0 );

 }
 

 void simu_miic_stop( const software_mi2c_t* i2c ){

	if (i2c->set_sda_mode) i2c->set_sda_mode( 0 );
	i2c->scl_out( 0 );
	i2c->sda_out( 0 ); 
	i2c->delay();   
	i2c->scl_out( 1 );
	i2c->delay();    
	i2c->sda_out( 1 );  
 }
 

 TU8 simu_miic_wait_ack( const software_mi2c_t* i2c ){

		TU8 ucErrTime = 0;
		if (i2c->set_sda_mode) i2c->set_sda_mode( 1 );
		i2c->sda_out( 1 );
		i2c->delay();
		i2c->scl_out( 1 );
		i2c->delay();
		while ( i2c->sda_in() )
		{
				i2c->delay();
				ucErrTime++;
				if ( ucErrTime > 20 )
				{
						i2c->scl_out( 0 );
						return 1u;
				}
		}
		i2c->scl_out( 0 );
		return 0u;
 }
 

 void simu_miic_generate_ack( const software_mi2c_t* i2c ){
 
    if(i2c->set_sda_mode) i2c->set_sda_mode( 0 );
    i2c->scl_out( 0 );
    i2c->sda_out( 0 );
    i2c->delay();   
    i2c->scl_out( 1 );
	  i2c->delay();      
    i2c->scl_out( 0 );
		
 }
 

 void simu_miic_generate_nack( const software_mi2c_t* i2c ){

    if (i2c->set_sda_mode) i2c->set_sda_mode(0);
    i2c->scl_out(0);
    i2c->sda_out(1);
    i2c->delay();
    i2c->scl_out(1);
    i2c->delay();
    i2c->scl_out(0);
		
 }
 

 void simu_miic_write_byte( const software_mi2c_t* i2c,TU8 data ){
 
    TU8 t;
    if (i2c->set_sda_mode)
        i2c->set_sda_mode( 0 );
    i2c->scl_out( 0 );
    for (t = 0; t < 8; t++)
    {
        i2c->sda_out((data & 0x80) >> 7);
#if ( 0U == USE_HIGH_SPEED )
        i2c->delay();
#endif

        i2c->scl_out( 1 );
        i2c->delay();
        data <<= 1;
        i2c->scl_out( 0 );
    }
 }
 

 TU8 simu_miic_read_byte( const software_mi2c_t* i2c,TU8 ack ){
 
    TU8 i, receive = 0;
    if (i2c->set_sda_mode)
        i2c->set_sda_mode( 1 );
    i2c->sda_out(1);

    for (i = 0; i < 8; i++)
    {
        i2c->scl_out( 0 );
        i2c->delay();
        receive <<= 1;
        i2c->scl_out( 1 );

#if ( 0U == USE_HIGH_SPEED )
        i2c->delay();
#endif
        if ( i2c->sda_in() )
            receive++;
    }
    i2c->scl_out( 0 );
    if (!ack)
        simu_miic_generate_nack( i2c ); 
    else
        simu_miic_generate_ack( i2c );
    return receive;
 }
 




TU8 simu_miic_dev_write(const software_mi2c_t *i2c, TU8 saddr, TU8 reg, TU8 *buf, TU8 len){
	
    TU8 i;

    saddr <<= 1;

    simu_miic_start(i2c);
    simu_miic_write_byte(i2c, SI2C_ADDR_W(saddr));
    if ( 0 != simu_miic_wait_ack(i2c) )
        goto _noack;
    simu_miic_write_byte(i2c, reg);
    if ( 0 != simu_miic_wait_ack(i2c) )
        goto _noack;

    for (i = 0; i < len; i++)
    {
        simu_miic_write_byte(i2c, buf[i]);
        if ( 0 != simu_miic_wait_ack(i2c) )
            goto _noack;
    }
    simu_miic_stop(i2c);
    return 0;

_noack: 
    simu_miic_stop(i2c);
    return 1;
}

TU8 simu_miic_dev_read(const software_mi2c_t *i2c, TU8 saddr, TU8 reg, TU8 *buf, TU8 len){
	
    TU8 i;
    saddr <<= 1;

    simu_miic_start(i2c);
    simu_miic_write_byte(i2c, SI2C_ADDR_W(saddr));
    if ( 0 != simu_miic_wait_ack(i2c) )
        goto _noack;
    simu_miic_write_byte(i2c, reg);
    if ( 0 != simu_miic_wait_ack(i2c) )
        goto _noack;
    simu_miic_start(i2c);
    simu_miic_write_byte(i2c, SI2C_ADDR_R(saddr));
    if ( 0 != simu_miic_wait_ack(i2c) )
        goto _noack;
    if (len == 1)
        buf[0] = simu_miic_read_byte(i2c, 0);
    else
        for (i = 0; i < len; i++)
        {
            buf[i] = simu_miic_read_byte(i2c, 1 - (i / (len - 1)));
        }
    simu_miic_stop(i2c);
    return 0;

_noack: 
    simu_miic_stop(i2c);
    return 1;
}


